﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;

using MissionEditor.ConditionUI;
using MissionEditor.EventUI;

namespace MissionEditor
{
    public partial class Form1 : Form
    {
        Mission mission = new Mission();
        string currentFilename = "";
        public Form1()
        {
            InitializeComponent();

            UpdateTitle();
        }
        void UpdateTitle()
        {
            if (string.IsNullOrEmpty(currentFilename))
                this.Text = "Dune 2000 Mission Editor";
            else
                this.Text = currentFilename + " - " + "Dune 2000 Mission Editor";
        }

        private void openButton_Click(object sender, EventArgs e)
        {
            //Let the user pick the files to parse
            OpenFileDialog dialog = new OpenFileDialog();
            dialog.Filter = "Dune 2000 mission files (*.mis)|*.mis";

            if (dialog.ShowDialog() == DialogResult.OK)
            {
                ParseMission(dialog.FileName);
            }
        }

        private void ParseMission(string filename)
        {
            currentFilename = Path.GetFileNameWithoutExtension(filename);
            UpdateTitle();
            mission.LoadFromFile(filename);

            UpdateEventListBox();
            UpdateConditionListBox();

            FillUIFromMission();
            EnableBoxes();
        }



        private void FillUIFromMission()
        {
            //Someone suggested this should all be abstracted. They were right tbh.
            for (int i = 0; i < 8; i++)
            {
                ((TextBox)this.Controls["techLevel" + (i + 1).ToString()]).Text = mission.houseTechLevel[i].ToString();
            }

            for (int i = 0; i < 8; i++)
            {
                ((TextBox)this.Controls["startingMoney" + (i + 1).ToString()]).Text = mission.startingMoney[i].ToString();
            }

            for (int i = 0; i < 8; i++)
            {
                ((TextBox)this.Controls["index" + (i + 1).ToString()]).Text = mission.houseIndexAllocation[i].ToString();
            }

            for (int i = 0; i < 8; i++)
            {
                for (int j = 0; j < 8; j++)
                {
                    ((ComboBox)this.Controls["comboBox" + (i + 1).ToString() + "to" + (j + 1).ToString()]).SelectedIndex = mission.diplomacy[i, j];
                }
            }
            tileSetDataTextBox.Text = Encoding.Default.GetString(mission.tilesetDataName);
            tileSetImageTextBox.Text = Encoding.Default.GetString(mission.tilesetImageName);
            timeLimitTextBox.Text = mission.timeLimit.ToString();
        }
        private void FillMissionFromUI()
        {
            for (int i = 0; i < 8; i++)
            {
                mission.houseTechLevel[i] = Convert.ToByte(((TextBox)this.Controls["techLevel" + (i + 1).ToString()]).Text);
            }

            for (int i = 0; i < 8; i++)
            {
                mission.startingMoney[i] = Convert.ToInt32(((TextBox)this.Controls["startingMoney" + (i + 1).ToString()]).Text);
            }

            for (int i = 0; i < 8; i++)
            {
                mission.houseIndexAllocation[i] = Convert.ToByte(((TextBox)this.Controls["index" + (i + 1).ToString()]).Text);
            }

            for (int i = 0; i < 8; i++)
            {
                for (int j = 0; j < 8; j++)
                {
                    mission.diplomacy[i, j] = (byte)((ComboBox)this.Controls["comboBox" + (i + 1).ToString() + "to" + (j + 1).ToString()]).SelectedIndex;
                }
            }
            byte[] buffer = new byte[200];
            byte[] newBuffer;
            
            newBuffer = Encoding.Default.GetBytes(tileSetDataTextBox.Text);
            newBuffer.CopyTo(buffer, 0);
            mission.tilesetDataName = buffer;


            buffer = new byte[200];
            newBuffer = Encoding.Default.GetBytes(tileSetImageTextBox.Text);
            newBuffer.CopyTo(buffer, 0);
            mission.tilesetImageName = buffer;

            mission.timeLimit = Convert.ToInt32(timeLimitTextBox.Text);
        }    

        private void EnableBoxes()
        {
            //Dirty code.
            for (int i = 0; i < 8; i++)
            {
                ((TextBox)this.Controls["techLevel" + (i + 1).ToString()]).Enabled = true;
            }

            for (int i = 0; i < 8; i++)
            {
                ((TextBox)this.Controls["startingMoney" + (i + 1).ToString()]).Enabled = true;
            }

            for (int i = 0; i < 8; i++)
            {
                ((TextBox)this.Controls["index" + (i + 1).ToString()]).Enabled = true;
            }

            for (int i = 0; i < 8; i++)
            {
                for (int j = 0; j < 8; j++)
                {
                    ((ComboBox)this.Controls["comboBox" + (i + 1).ToString() + "to" + (j + 1).ToString()]).Enabled = true;
                }
            }
            saveButton.Enabled = true;
            tileSetDataTextBox.Enabled = true;
            tileSetImageTextBox.Enabled = true;
            timeLimitTextBox.Enabled = true;

            applyEventChangesButton.Enabled = true;
            applyConditionChangesButton.Enabled = true;
            eventPanel.Controls.Clear();
            conditionPanel.Controls.Clear();
            eventConditionMappingTableLayoutPanel.RowCount = 0;
            eventConditionMappingTableLayoutPanel.Controls.Clear();
            selectedEventTitle.Text = "";
            selectedConditionTitle.Text = "";

            changeEventTypeButton.Enabled = true;
            changeConditionTypeButton.Enabled = true;

            addEventButton.Enabled = true;
            addConditionButton.Enabled = true;

            deleteEventButton.Enabled = true;
            deleteConditionButton.Enabled = true;

            addMappingButton.Enabled = true;
            deleteLastMappingButton.Enabled = true;

            importAISegmentButton.Enabled = true;
            exportAISegmentButton.Enabled = true;
        }

        private void saveButton_Click(object sender, EventArgs e)
        {
            //Let the user pick the files to parse
            SaveFileDialog dialog = new SaveFileDialog();
            dialog.FileName = currentFilename;
            dialog.Filter = "Dune 2000 mission files (*.mis)|*.mis";

            if (dialog.ShowDialog() == DialogResult.OK)
            {
                FillMissionFromUI();


                SaveMission(dialog.FileName);
            }
        }

        private void SaveMission(string filename)
        {
            mission.SaveToFile(filename);
        }

        private void addEventButton_Click(object sender, EventArgs e)
        {
            if (mission.eventCount < 64)
            {
                mission.eventCount++;
                mission.events[mission.eventCount - 1] = new Event();
                UpdateEventListBox();
                eventPanel.Controls.Clear();
                eventConditionMappingTableLayoutPanel.Controls.Clear();
            }
        }

        private void UpdateEventListBox()
        {
            eventListBox.Items.Clear();
            for (int i = 0; i < mission.eventCount; i++)
            {
                eventListBox.Items.Add(i.ToString() + " - " + Mission.GetEventDescriptionFromIndex(mission.events[i].raw[13]));
            }
        }
        private void UpdateConditionListBox()
        {
            conditionListBox.Items.Clear();
            for (int i = 0; i < mission.conditionCount; i++)
            {
                conditionListBox.Items.Add(i.ToString() + " - " + Mission.GetConditionDescriptionFromIndex(mission.conditions[i].raw[25]));
            }
        }

        private void addConditionButton_Click(object sender, EventArgs e)
        {
            if (mission.conditionCount < 48)
            {
                mission.conditionCount++;
                mission.conditions[mission.conditionCount - 1] = new Condition();
                UpdateConditionListBox();
                conditionPanel.Controls.Clear();
            }
        }

        private void conditionListBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (conditionListBox.SelectedIndex == -1)
                return;
            Condition condition = mission.conditions[conditionListBox.SelectedIndex];
            selectedConditionTitle.Text = conditionListBox.SelectedItem.ToString();
            conditionPanel.Controls.Clear();
            switch (condition.raw[25])
            {
                case 0:
                    conditionPanel.Controls.Add(new BuildingExists(condition));
                    break;
                case 1:
                    conditionPanel.Controls.Add(new UnitExists(condition));
                    break;
                case 2:
                    conditionPanel.Controls.Add(new Interval(condition));
                    break;
                case 3:
                    conditionPanel.Controls.Add(new ConditionUI.Timer(condition));
                    break;
                case 4:
                    conditionPanel.Controls.Add(new Casualties(condition));
                    break;
                case 5:
                    conditionPanel.Controls.Add(new BaseDestroyed(condition));
                    break;
                case 6:
                    conditionPanel.Controls.Add(new UnitsDestroyed(condition));
                    break;
                case 7:
                    conditionPanel.Controls.Add(new UnitInTile(condition));
                    break;
                case 8:
                    conditionPanel.Controls.Add(new Cash(condition));
                    break;
                case 9:
                    conditionPanel.Controls.Add(new Dummy(condition));
                    break;

                default:
                    break;
            }            
        }

        private void applyConditionChangesButton_Click(object sender, EventArgs e)
        {
            if (conditionPanel.Controls.Count == 1)
                ((IConditionUI)conditionPanel.Controls[0]).Apply();
        }

        private void eventListBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (eventListBox.SelectedIndex == -1)
                return;
            Event selectedEvent = mission.events[eventListBox.SelectedIndex];
            selectedEventTitle.Text = eventListBox.SelectedItem.ToString();

            UpdateConditionMappingTable();


            eventPanel.Controls.Clear();
            switch (selectedEvent.raw[13])
            {
                case 0:
                    eventPanel.Controls.Add(new Reinforcement(selectedEvent));
                    break;
                case 1:
                    eventPanel.Controls.Add(new StarportDelivery(selectedEvent));
                    break;
                case 2:
                    eventPanel.Controls.Add(new Diplomacy(selectedEvent));
                    break;
                case 4:
                    eventPanel.Controls.Add(new Beserk(selectedEvent));
                    break;
                case 6:
                    eventPanel.Controls.Add(new Unknown6(selectedEvent));
                    break;
                case 10:
                    eventPanel.Controls.Add(new MissionWin(selectedEvent));
                    break;
                case 11:
                    eventPanel.Controls.Add(new MissionWin(selectedEvent));
                    break;
                case 14:
                    eventPanel.Controls.Add(new RevealMap(selectedEvent));
                    break;
                case 16:
                    eventPanel.Controls.Add(new TimeLimitDisable(selectedEvent));
                    break;
                case 17:
                    eventPanel.Controls.Add(new EventUI.Message(selectedEvent));
                    break;
                case 18:
                    eventPanel.Controls.Add(new UnitSpawn(selectedEvent));
                    break;
                case 19:
                    eventPanel.Controls.Add(new SetCondition(selectedEvent));
                    break;
                
                default:
                    break;
            }
        }

        private void UpdateConditionMappingTable()
        {
            eventConditionMappingTableLayoutPanel.Controls.Clear();
            if (eventListBox.SelectedIndex >= 0)
            {
                Event selectedEvent = mission.events[eventListBox.SelectedIndex];

                int numberOfMappings = selectedEvent.raw[12];
                eventConditionMappingTableLayoutPanel.ColumnCount = 2;
                //eventConditionMappingTableLayoutPanel.RowCount = numberOfMappings;

                for (int i = 0; i < numberOfMappings; i++)
                {
                    CheckBox checkBox = new CheckBox();
                    //checkBox.AutoSize = true;
                    checkBox.Width = 140;
                    checkBox.Text = conditionListBox.Items[selectedEvent.raw[19 + i]].ToString();
                    checkBox.Checked = selectedEvent.raw[33 + i] == 1;
                    checkBox.Name = "CheckBox" + i;
                    checkBox.CheckedChanged += new EventHandler(checkBox_CheckedChanged);
                    eventConditionMappingTableLayoutPanel.Controls.Add(checkBox, 0, i);
                    Button button = new Button();
                    button.Name = "MappingButton" + i;
                    button.Click += new EventHandler(mappingButton_Click);
                    button.Text = "Set Index";
                    eventConditionMappingTableLayoutPanel.Controls.Add(button, 1, i);
                }
            }
        }

        private void checkBox_CheckedChanged(object sender, EventArgs e)
        {
            Event selectedEvent = mission.events[eventListBox.SelectedIndex];
            int index = Convert.ToInt32(((CheckBox)sender).Name.Substring("CheckBox".Length));

            selectedEvent.raw[33 + index] = (byte)((selectedEvent.raw[33 + index] == 1) ? 0 : 1);
        }
        private void mappingButton_Click(object sender, EventArgs e)
        {
            Event selectedEvent = mission.events[eventListBox.SelectedIndex];
            int index = Convert.ToInt32(((Button)sender).Name.Substring("MappingButton".Length));

            string result = selectedEvent.raw[19 + index].ToString();
            if (Extensions.InputBox("Change Event-Condition Mapping", "Changing this value will change the mapping entry's target condition.\nBe careful that you map it to a real condition.", ref result) == DialogResult.OK)
            {
                selectedEvent.raw[19 + index] = Convert.ToByte(result);
                UpdateConditionMappingTable();
            }
        }
        
        private void applyEventChangesButton_Click(object sender, EventArgs e)
        {
            if(eventPanel.Controls.Count == 1)
                ((IEventUI)eventPanel.Controls[0]).Apply();
        }

        private void addMappingButton_Click(object sender, EventArgs e)
        {
            if (eventListBox.SelectedIndex >= 0)
            {
                Event selectedEvent = mission.events[eventListBox.SelectedIndex];

                int mappingCount = selectedEvent.raw[12];
                if (mappingCount < 14)
                {
                    selectedEvent.raw[12]++;
                    selectedEvent.raw[19 + mappingCount] = 0;
                    selectedEvent.raw[33 + mappingCount] = 0;
                    UpdateConditionMappingTable();
                }
            }
        }

        private void toolStripStatusLabel2_Click(object sender, EventArgs e)
        {
            System.Diagnostics.Process.Start("www.mvinetwork.co.uk/dune"); 
        }

        private void aboutButton_Click(object sender, EventArgs e)
        {
            AboutWindow window = new AboutWindow();
            window.ShowDialog();
        }

        private void changeEventTypeButton_Click(object sender, EventArgs e)
        {
            if (eventListBox.SelectedIndex >= 0)
            {
                Event selectedEvent = mission.events[eventListBox.SelectedIndex];
                SelectEventTypeDialog dialog = new SelectEventTypeDialog(selectedEvent.raw[13]);
                if (dialog.ShowDialog() == DialogResult.OK)
                {
                    mission.events[eventListBox.SelectedIndex] = new Event();
                    mission.events[eventListBox.SelectedIndex].raw[13] = (byte)dialog.EventCode;
                    UpdateEventListBox();
                    eventPanel.Controls.Clear();
                    eventConditionMappingTableLayoutPanel.Controls.Clear();
                }
            }
        }

        private void deleteLastMappingButton_Click(object sender, EventArgs e)
        {
            if (eventListBox.SelectedIndex >= 0)
            {
                Event selectedEvent = mission.events[eventListBox.SelectedIndex];

                int mappingCount = selectedEvent.raw[12];
                if (mappingCount > 1)
                {
                    selectedEvent.raw[12]--;
                    UpdateConditionMappingTable();
                }
            }
        }

        private void changeConditionTypeButton_Click(object sender, EventArgs e)
        {
            if (conditionListBox.SelectedIndex >= 0)
            {
                Condition selectedCondition = mission.conditions[conditionListBox.SelectedIndex];
                SelectConditionTypeDialog dialog = new SelectConditionTypeDialog(selectedCondition.raw[25]);
                if (dialog.ShowDialog() == DialogResult.OK)
                {
                    mission.conditions[conditionListBox.SelectedIndex] = new Condition();
                    mission.conditions[conditionListBox.SelectedIndex].raw[25] = (byte)dialog.ConditionCode;
                    UpdateConditionListBox();
                    conditionPanel.Controls.Clear();
                }
            }
        }

        private void deleteEventButton_Click(object sender, EventArgs e)
        {
            if (eventListBox.SelectedIndex >= 0)
            {
                for (int i = eventListBox.SelectedIndex; i < mission.eventCount-1; i++)
                {
                    mission.events[i] = mission.events[i + 1];
                }
                mission.eventCount--;
                UpdateEventListBox();
                eventPanel.Controls.Clear();
                eventConditionMappingTableLayoutPanel.Controls.Clear();
            }
        }

        private void deleteConditionButton_Click(object sender, EventArgs e)
        {
            if (conditionListBox.SelectedIndex >= 0)
            {
                int selectedIndex = conditionListBox.SelectedIndex;
                for (int i = conditionListBox.SelectedIndex; i < mission.conditionCount - 1; i++)
                {
                    mission.conditions[i] = mission.conditions[i + 1];
                }
                mission.conditionCount--;
                UpdateConditionListBox();
                conditionPanel.Controls.Clear();
                if (MessageBox.Show("Do you wish to update the event-condition mappings?\n\nThis is STRONGLY advised unless you are an advanced\nuser who knows exactly what you're doing.", "Update Event-Condition Mappings?", MessageBoxButtons.YesNo) == DialogResult.Yes)
                {
                    // TODO: Update

                    for (int j = 0; j < mission.eventCount; j++)
                    {
                        int mappingCount = mission.events[j].raw[12];

                        for (int k = 0; k < mappingCount; k++)
                        {
                            if (mission.events[j].raw[19 + k] > selectedIndex)
                            {
                                mission.events[j].raw[19 + k]--;
                            }
                        }
                    }
                    UpdateConditionMappingTable();
                }
            }
        }

        private void exportAISegmentButton_Click(object sender, EventArgs e)
        {
            string sideIndexString = "0";
            if (Extensions.InputBox("Select Side", "Please select a side index to export AI from.", ref  sideIndexString) == DialogResult.OK)
            {
                int sideIndex = Convert.ToInt32(sideIndexString);
                if(sideIndex >= 0 && sideIndex < 8)
                {
                    SaveFileDialog dialog = new SaveFileDialog();
                    dialog.FileName = currentFilename + "Seg" + sideIndex;
                    dialog.Filter = "D2K+ AI Segment files (*.misai)|*.misai";

                    if (dialog.ShowDialog() == DialogResult.OK)
                    {
                        ExportAISegment(sideIndex, dialog.FileName);
                    }
                }
                else
                {
                    MessageBox.Show("Please select a side index between 0 and 7");
                }
            }
        }

        private void ExportAISegment(Mission mission, int sideIndex, string filename)
        {
            FileStream fs = new FileStream(filename, FileMode.Create);
            BinaryWriter bw = new BinaryWriter(fs);
            byte[] buffer = new byte[7607];
            for (int i = 0; i < 7607; i++)
            {
                buffer[i] = mission.ai[sideIndex, i + 1];
            }
            bw.Write(buffer);
            bw.Close();
            fs.Close();
            //MessageBox.Show("Exported side " + sideIndex + " as " + Path.GetFileName(filename));
        }
        private void ExportAISegment(int sideIndex, string filename)
        {
            FileStream fs = new FileStream(filename, FileMode.Create);
            BinaryWriter bw = new BinaryWriter(fs);
            byte[] buffer = new byte[7607];
            for (int i = 0; i < 7607; i++)
            {
                buffer[i] = mission.ai[sideIndex, i + 1];
            }
            bw.Write(buffer);
            bw.Close();
            fs.Close();
            MessageBox.Show("Exported side " + sideIndex + " as " + Path.GetFileName(filename));
        }

        private void importAISegmentButton_Click(object sender, EventArgs e)
        {
            string sideIndexString = "0";
            if (Extensions.InputBox("Select Side", "Please select a side index to OVERWRITE with AI from file.", ref  sideIndexString) == DialogResult.OK)
            {
                int sideIndex = Convert.ToInt32(sideIndexString);
                if (sideIndex >= 0 && sideIndex < 8)
                {
                    OpenFileDialog dialog = new OpenFileDialog();
                    dialog.FileName = currentFilename + "Seg" + sideIndex;
                    dialog.Filter = "D2K+ AI Segment files (*.misai)|*.misai";

                    if (dialog.ShowDialog() == DialogResult.OK)
                    {
                        ImportAISegment(sideIndex, dialog.FileName);
                    }
                }
                else
                {
                    MessageBox.Show("Please select a side index between 0 and 7");
                }
            }
        }

        private void ImportAISegment(int sideIndex, string filename)
        {
            FileStream fs = new FileStream(filename, FileMode.Open);
            BinaryReader br = new BinaryReader(fs);
            byte[] buffer = new byte[7607];
            br.Read(buffer, 0, 7607);
            br.Close();
            fs.Close();
            mission.ai[sideIndex, 0] = (byte)sideIndex;
            for (int i = 0; i < 7607; i++)
            {
                mission.ai[sideIndex, i + 1] = buffer[i];
            }
            MessageBox.Show("Overwrote side " + sideIndex + " with " + Path.GetFileName(filename));
        }

        private void button1_Click(object sender, EventArgs e)
        {
            //Let the user pick the files to parse
            OpenFileDialog dialog = new OpenFileDialog();
            dialog.Filter = "Dune 2000 mission files (*.mis)|*.mis";
            dialog.Multiselect = true;
            if (dialog.ShowDialog() == DialogResult.OK)
            {
                for (int i = 0; i < dialog.FileNames.Length; i++)
                {
                    Mission mission = new Mission();
                    mission.LoadFromFile(dialog.FileNames[i]);
                    for (int j = 0; j < 8; j++)
                    {
                        string filename = Path.GetFileNameWithoutExtension(dialog.FileNames[i]);
                        string path = Path.GetDirectoryName(dialog.FileNames[i]);
                        filename = path + "\\" + filename + "-" + j.ToString() + ".misai";
                        ExportAISegment(mission, j, filename);
                    }
                } 
                
            }
            MessageBox.Show("Exported sides");
        }

    }
}
